﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace CefGlue.Avalonia.Javascript
{
    public class JavascriptObjectInfo
    {
        public int ObjectId { get; set; }

        public string Name { get; set; }

        public string ObjectTypeName { get; set; }

        public string AssemblyName { get; set; }
        public object Object { get; set; }
        public List<JavascriptMethodInfo> JavascriptMethods { get; set; } = new List<JavascriptMethodInfo>();
    }

    public class JavascriptMethodInfo
    {
        public string MethodName { get; set; }

        public string[] ArgNames
        {
            get;
            set;
        }
    }

    public class JavascriptRepository
    {
        public static ConcurrentDictionary<int, JavascriptObjectInfo> JavascriptMap = new ConcurrentDictionary<int, JavascriptObjectInfo>();

        public List<JavascriptObjectInfo> GetAll()
        {
            return JavascriptMap.Values.ToList();
        }
        public void RegisterJavascriptObject(string name, object obj)
        {
            if (obj == null || string.IsNullOrWhiteSpace(name))
            {
                return;
            }
            int objectId = JavascriptMap.Count + 1;
            Type objType = obj.GetType();
            JavascriptObjectInfo javascriptObjectInfo = new JavascriptObjectInfo();
            javascriptObjectInfo.Object = obj;
            javascriptObjectInfo.ObjectTypeName = objType.FullName;
            javascriptObjectInfo.AssemblyName = objType.Assembly.GetName().FullName;
            javascriptObjectInfo.ObjectId = objectId;
            javascriptObjectInfo.Name = name;
            var methods = objType.GetMethods(BindingFlags.Instance | BindingFlags.Public);

            foreach (var method in methods)
            {
                var paramInfos = method.GetParameters();
                List<string> paramList = new List<string>();
                foreach (var paramInfo in paramInfos.OrderBy(t => t.Position))
                {
                    paramList.Add(paramInfo.Name);
                    //Console.WriteLine($"Position={paramInfo.Position},Name={paramInfo.Name},Type={paramInfo.ParameterType.FullName},defaultValue={paramInfo.DefaultValue}");
                }
                JavascriptMethodInfo javascriptMethodInfo = new JavascriptMethodInfo();
                javascriptMethodInfo.MethodName = method.Name;
                javascriptMethodInfo.ArgNames = paramList.ToArray();
                javascriptObjectInfo.JavascriptMethods.Add(javascriptMethodInfo);
            }
            JavascriptMap.AddOrUpdate(objectId, (id) =>
            {
                return javascriptObjectInfo;
            },
            (id, v) =>
            {
                return javascriptObjectInfo;
            });
        }
    }
}
